home *** CD-ROM | disk | FTP | other *** search
/ Technotools / Technotools (Chestnut CD-ROM)(1993).ISO / lang_c / 13h_kit / images.cpp < prev    next >
C/C++ Source or Header  |  1991-07-04  |  67KB  |  2,050 lines

  1. //**************************************************************************
  2. // IMAGES.CPP -source file for basic video operations in mode 0x13.        *
  3. // Copyright 1991 by the Gamers Programming Workshop, a function of the    *
  4. // GAMERS forum, Compuserve. For more info e-mail 76605,2346.              *
  5. //                                                                         *
  6. // License is granted for use or modification of this code as long as      *
  7. // this notice remains intact, and all improvements are listed in the      *
  8. // version history below, and uploaded to the GAMERS forum. This code      *
  9. // may not be used for any commercial purpose.                             *
  10. //                                                                         *
  11. // PCX stuff adapted from "BitMapped Graphics"  by Steve Rimmer (1990      *
  12. // Windcrest)                                                              *
  13. //**************************************************************************
  14.  
  15. //**************************************************************************
  16. // Version history:                                                        *
  17. //                                                                         *
  18. // Version 1.0                                                             *
  19. // Developed: May 2, 1991                                                  *
  20. // Author:    Mark Betz, 76605, 2346                                       *
  21. // Last update: July 5, 1991                                               *
  22. //**************************************************************************
  23.  
  24. // INCLUDES ****************************************************************
  25.  
  26. #include <stdio.h>
  27. #include <conio.h>
  28. #include <dos.h>
  29. #include <mem.h>
  30. #include <alloc.h>
  31. #include <io.h>
  32. #include <fcntl.h>
  33. #include "images.hpp"
  34. #include "keyboard.hpp"
  35.  
  36. // *************************************************************************
  37.  
  38. // local constants *********************************************************
  39.  
  40. const int DacWrite = 0x3C8;        // DAC write index register
  41. const int DacRead  = 0x3C7;        // DAC read index register
  42. const int DacData  = 0x3C9;        // DAC data register
  43. const int input_status_1 = 0x3DA;  // Port addr. of VGA input status 1 reg.
  44. const int vbi_mask = 0x8;          // test bit 3 of input_status_1
  45.  
  46. // *************************************************************************
  47.  
  48. // Variables ***************************************************************
  49.  
  50. static unsigned int GRAPH_SEG = 0xA000; // segment for video operations
  51. static p_rec current;                   // palette record for fades
  52.  
  53. // *************************************************************************
  54.  
  55. // *************************************************************************
  56. // *************************************************************************
  57. // NOTE:
  58. //        The assembler functions in this module do not save any of the
  59. //        registers they use, with the exception of di and si, which are
  60. //        handled by the standard stack frame. When calling them expect
  61. //        register values to be altered.
  62. //
  63. // *************************************************************************
  64. // *************************************************************************
  65.  
  66. // *************************************************************************
  67. // reporterr() should be called anytime one of the routines in this module
  68. // returns a code other that NoErr. Pass it the error code returned by the
  69. // offending subroutine, and a max. 30 character string describing the loc-
  70. // ation of the error.
  71. // *************************************************************************
  72.  
  73. void reporterr(char type, char mess[30])
  74.     {
  75.     settextmode();
  76.     sound(300);
  77.     delay(200);
  78.     sound(250);
  79.     delay(150);
  80.     nosound();
  81.     switch (type)
  82.         {
  83.         case MemErr        : printf("An error occured allocating memory...");
  84.                              break;
  85.         case FileReadErr   : printf("An error occured reading a file...");
  86.                              break;
  87.         case FileWriteErr  : printf("An error occured writing a file...");
  88.                              break;
  89.         case FileMakeErr   : printf("An error occured creating a file...");
  90.                              break;
  91.         case FileOpenErr   : printf("An error occured opening a file...");
  92.                              break;
  93.         case FileFormatErr : printf("A file format error has occured...");
  94.                              break;
  95.         case SecondaryErr  : printf("An error has occured in a subroutine...");
  96.                              break;
  97.         case UnknownErr    : printf("An unknown error has occured...");
  98.         }
  99.     printf(" error occured in ");
  100.     printf(mess);
  101.     return;
  102.     }
  103.  
  104. // *************************************************************************
  105. // UnpackPcx() unpacks the RLE encoded PCX data from a file if pcx != NULL,
  106. // or the source buffer if pcx==NULL, to the Dest buffer. Unpacks NumBytes
  107. // bytes of decompressed data. (max 64000) This is a pretty dumb routine.
  108. // It's fast, but it expects you to know the uncompressed size of the data
  109. // (the NumBytes parameter), and you have to do all of the file and buffer
  110. // set-up elsewhere. Basically it's a core decoding engine. The InitPcxFile()
  111. // function above is provided for opening a PCX file and saving the header
  112. // and palette in data. For buffering and decoding of pcx's with various
  113. // fade types see the fadeinpcx() function below.
  114. // *************************************************************************
  115.  
  116. // *************************************************************************
  117. // NOTE: this function isn't called by the PVC class objects when they dis-
  118. // play themselves. It is an earlier version of the algrotihm, and they have
  119. // their own version of it. I left this in in case anyone wanted to use it.
  120. // **************************************************************************
  121.  
  122. void  unpackpcx(FILE *pcx, const char far *source, char far *dest,
  123.                 unsigned int num_bytes)
  124.     {
  125.     unsigned int     bytes=0;       // counts unpacked bytes
  126.     unsigned char    c;             // byte being processed
  127.     unsigned int     src_cntr=0;    // pointer into source buffer
  128.     unsigned int     runlen;        // length of packet
  129.  
  130.     do
  131.         {
  132.         // get a key byte
  133.         if (pcx!=NULL)
  134.            c=fgetc(pcx);
  135.         else
  136.            c=source[src_cntr++] & 0xff;
  137.         // check if it's a packet
  138.         if ((c & 0xc0) == 0xc0)
  139.             {
  140.             // and off the high bits
  141.             runlen = (c & 0x3f);
  142.             // get the run value
  143.             if (pcx!=NULL)
  144.                 c=fgetc(pcx);
  145.             else
  146.                 c = source[src_cntr++];
  147.             // run it out
  148.             while(runlen--) (dest[bytes++]=c);
  149.             }
  150.         else
  151.             dest[bytes++]=c;
  152.         } while (bytes<num_bytes);
  153.     }
  154.  
  155. // *************************************************************************
  156. // sets the segment address that will be used in all graphics operations
  157. // within this module. Can be used to operate on a buffer offscreen. This
  158. // is a fairly powerfull feature, as any of the functions provided which
  159. // write or read video memory will act on the segment contained in GRAPH_
  160. // SEG. If you allocate a 64k buffer, and call _setgraphseg() with it's
  161. // segment you can then create the screen there, and block copy it to
  162. // video ram when you're finished.
  163. // *************************************************************************
  164.  
  165. void setgraphseg(unsigned int newseg)
  166.     {
  167.     GRAPH_SEG = newseg;
  168.     }
  169.  
  170. // *************************************************************************
  171. // call bios interrupt 0x10, function 13, subfunction 00 to set up mode
  172. // 0x13 graphics.
  173. // *************************************************************************
  174.  
  175. void setgraphmode()
  176.     {
  177.     asm    {
  178.         xor ah, ah          // zero out ah, subfunction 00
  179.         mov al, 0x13        // function 0x13
  180.         int 0x10            // interrupt 0x10
  181.         }
  182.     }
  183.  
  184. // *************************************************************************
  185. // call bios interrupt 0x10 in same manner as previous function to restore
  186. // text mode
  187. // *************************************************************************
  188.  
  189. void settextmode()
  190.     {
  191.     asm    {
  192.         xor ah, ah
  193.         mov al, 0x03
  194.         int 0x10
  195.         }
  196.     }
  197.  
  198. // **************************************************************************
  199. // wait_vbi() waits twice for the vertical blanking interval. Once to make
  200. // sure any current vbi is completed, and once for the start of the next vbi
  201. // **************************************************************************
  202.  
  203. void wait_vbi()
  204.     {
  205.     asm mov dx, input_status_1;
  206.     test_1:
  207.     asm    {
  208.         in al, dx
  209.         test al,0x8
  210.         jnz test_1
  211.         }
  212.     test_2:
  213.     asm    {
  214.         in al, dx
  215.         test al,0x8
  216.         jz test_2
  217.         }
  218.     }
  219.  
  220.  
  221. // *************************************************************************
  222. // loads the vga dac by direct method via the DAC access ports. Disables
  223. // interrupts during load of each triplet. Does not do snow checking. Call
  224. // with start = first register to load, number = number of registers to
  225. // load, and palette pointing to a structure of type PRec containing the
  226. // palette data. If start or number out of range, or palette is null then
  227. // the function returns.
  228. // *************************************************************************
  229.  
  230. void loadpalette(int start, int number, const p_rec palette)
  231.     {
  232.     unsigned int i;
  233.     if ((start>256) || (start<0) || ((start+number)>256))
  234.         return;
  235.     for (i=start;i<(start+number);i++)
  236.         {
  237.         asm cli;
  238.         outportb(DacWrite,i);
  239.         outportb(DacData,palette[i][Red]);
  240.         outportb(DacData,palette[i][Green]);
  241.         outportb(DacData,palette[i][Blue]);
  242.         asm sti;
  243.         }
  244.     }
  245.  
  246. // *************************************************************************
  247. // same as previous function only reads the dac data into the supplied
  248. // palette structure.
  249. // *************************************************************************
  250.  
  251. void readpalette(int start, int number, p_rec palette)
  252.     {
  253.     unsigned int i;
  254.     if ((start>256) | (start<0) | ((start+number)>256))
  255.         return;
  256.     for (i=start;i<(start+number);i++)
  257.         {
  258.         asm cli;
  259.         outportb(DacRead,i);
  260.         palette[i][Red] = inportb(DacData);
  261.         palette[i][Green] = inportb(DacData);
  262.         palette[i][Blue] = inportb(DacData);
  263.         asm sti;
  264.         }
  265.     }
  266.  
  267. // **************************************************************************
  268. // clears a range of palette registers to zero
  269. // **************************************************************************
  270.  
  271. void clrpalette(int start, int number)
  272.     {
  273.     unsigned int i;
  274.     if ((start>256) | (start<0) | ((start+number)>256))
  275.         return;
  276.     for (i=start;i<(start+number);i++)
  277.         {
  278.         asm cli;
  279.         outportb(DacWrite,i);
  280.         outportb(DacData,0);
  281.         outportb(DacData,0);
  282.         outportb(DacData,0);
  283.         asm sti;
  284.         }
  285.     }
  286.  
  287. // **************************************************************************
  288. // fadepalettein() fades the dac palette from 0 (black) to the default pal-
  289. // ette values passed in palette structure. Fade is done in 64 passes, and
  290. // is very smooth. Operates on count registers starting with register start.
  291. // NOTE: this funtion expect the dac palette registers to be zero'd before
  292. // it is called. Call clrpalette() to clear the registers.
  293. // **************************************************************************
  294.  
  295. void fadepalettein(int start, int count, const p_rec palette)
  296.     {
  297.     int i, j, cycle;
  298.     memset((void *)current,0,sizeof(p_rec));
  299.     for (cycle=0;cycle<64;cycle++)
  300.         {
  301.         i=start;
  302.         wait_vbi();
  303.         outportb(DacWrite,i);
  304.         asm cli;
  305.         for (;i<((start+count)/2);i++)
  306.             {
  307.             for (j=0;j<3;j++)
  308.                 {
  309.                 if ((64-cycle)<=palette[i][j])
  310.                     current[i][j]++;
  311.                 outportb(DacData,current[i][j]);
  312.                 }
  313.             }
  314.         asm sti;
  315.         wait_vbi();
  316.         asm cli;
  317.         for (;i<(start+count);i++)
  318.             {
  319.             for (j=0;j<3;j++)
  320.                 {
  321.                 if ((64-cycle)<=palette[i][j])
  322.                     current[i][j]++;
  323.                 outportb(DacData,current[i][j]);
  324.                 }
  325.             }
  326.         asm sti;
  327.         }
  328.     }
  329.  
  330. // **************************************************************************
  331. // fadepaletteout() fades the current palette to black. It operates on count
  332. // registers starting with register start. NOTE: this function destroys the
  333. // current contents of temp_pal (images.cpp internal palette structure).
  334. // **************************************************************************
  335.  
  336. void fadepaletteout(int start, int count)
  337.     {
  338.     int i, j, cycle;
  339.     readpalette(0,256,current);
  340.     for (cycle=64;cycle>0;cycle--)
  341.         {
  342.         i=start;
  343.         wait_vbi();
  344.         outportb(DacWrite,i);
  345.         asm cli;
  346.         for (;i<((start+count)/2);i++)
  347.             {
  348.             for (j=0;j<3;j++)
  349.                 {
  350.                 if (current[i][j]!=0)
  351.                     current[i][j]--;
  352.                 outportb(DacData,current[i][j]);
  353.                 }
  354.             }
  355.         asm sti;
  356.         wait_vbi();
  357.         asm cli;
  358.         for (;i<(start+count);i++)
  359.             {
  360.             for (j=0;j<3;j++)
  361.                 {
  362.                 if (current[i][j]!=0)
  363.                     current[i][j]--;
  364.                 outportb(DacData,current[i][j]);
  365.                 }
  366.             }
  367.         asm sti;
  368.         }
  369.     clearscr(0);
  370.     }
  371.  
  372. // *************************************************************************
  373. // clear the graphics screen to the color provided
  374. // *************************************************************************
  375.  
  376. void clearscr(int color)
  377.     {
  378.     asm {
  379.         mov es, GRAPH_SEG
  380.         xor di, di
  381.         mov ax, color
  382.         mov cx, 32000
  383.         rep stosw
  384.         }
  385.     }
  386.  
  387. // *************************************************************************
  388. // fill the rectangular area bounded by (tlx,tly)(brx,bry) with color.
  389. // tlx = top left x, tly = top left y, brx = bottom right x, bry = bottom
  390. // right y.
  391. //
  392. // This function needs to be recoded in assembler
  393. // *************************************************************************
  394.  
  395. void barfill(int tlx, int tly, int brx, int bry, int color)
  396.     {
  397.     int row;
  398.     void far *line;
  399.     for (row=tly;row<bry;row++)
  400.         {
  401.         line = MK_FP(GRAPH_SEG,((row*320)+tlx));
  402.         _fmemset(line,color,(brx-tlx));
  403.         }
  404.     }
  405.  
  406. // *************************************************************************
  407. // set the pixel at coordinate x,y to color
  408. // This could be translated into assembler, but is probably fast enough
  409. // *************************************************************************
  410.  
  411. void writepixel(int x, int y, int color)
  412.     {
  413.     *(char far *)MK_FP(GRAPH_SEG,(y*320)+x)=color;
  414.     }
  415.  
  416. // *************************************************************************
  417. // read the color of the pixel at coordinate x,y
  418. // Could also be done in assembler, but may be fast enough as is
  419. // *************************************************************************
  420.  
  421. char readpixel(int x, int y)
  422.     {
  423.     return(*(char far *)MK_FP(GRAPH_SEG,(y*320)+x));
  424.     }
  425.  
  426. // *************************************************************************
  427. // returns a void type pointer to video memory at pixel coordinate x,y
  428. // *************************************************************************
  429.  
  430. void far *xy_to_ptr(int x, int y)
  431.     {
  432.     return((char *)MK_FP(GRAPH_SEG,(y*320)+x));
  433.     }
  434.  
  435. // *************************************************************************
  436. // The following three functions make up the line drawing routine
  437. //
  438. // Draws a line in vga mode 13h only from (x0,y0) to (x1,y1) in color color.
  439. // Drawing code adapted from Power Graphics Programming, Michael Abrash
  440. // *************************************************************************
  441.  
  442. // *************************************************************************
  443. // Octant0() and Octant1() are support functions for line()
  444. // Adapted from "Power Graphics Programming", Michael Abrash.
  445. // *************************************************************************
  446.  
  447. void static near Octant0(unsigned int x0,unsigned int y0,unsigned int deltaX,
  448.              unsigned int deltaY, int Xdirection, int color)
  449.     {
  450.     int deltaYx2;
  451.     int deltaYx2minusdeltaXx2;
  452.     int errorterm;
  453.  
  454.     deltaYx2 = deltaY*2;
  455.     deltaYx2minusdeltaXx2=deltaYx2-(int)(deltaX*2);
  456.     errorterm=deltaYx2-(int)deltaX;
  457.  
  458.     writepixel(x0,y0,color);
  459.     while (deltaX--)
  460.         {
  461.         if (errorterm>=0)
  462.             {
  463.             y0++;
  464.             errorterm+=deltaYx2minusdeltaXx2;
  465.             }
  466.         else
  467.             errorterm+=deltaYx2;
  468.         x0+=Xdirection;
  469.         writepixel(x0,y0,color);
  470.         }
  471.     }
  472.  
  473. void static near Octant1(unsigned int x0,unsigned int y0,unsigned int deltaX,
  474.              unsigned int deltaY, int Xdirection, int color)
  475.     {
  476.  
  477.     int deltaXx2;
  478.     int deltaXx2minusdeltaYx2;
  479.     int errorterm;
  480.  
  481.     deltaXx2=deltaX*2;
  482.     deltaXx2minusdeltaYx2=deltaXx2-(int)(deltaY*2);
  483.     errorterm=deltaXx2-(int)deltaY;
  484.  
  485.     writepixel(x0,y0,color);
  486.     while (deltaY--)
  487.         {
  488.         if (errorterm>=0)
  489.             {
  490.             x0+=Xdirection;
  491.             errorterm+=deltaXx2minusdeltaYx2;
  492.             }
  493.         else
  494.             errorterm+=deltaXx2;
  495.         y0++;
  496.         writepixel(x0,y0,color);
  497.         }
  498.     }
  499.  
  500. // **************************************************************************
  501. // takes the initial call and manages the line drawing
  502. // Adapted from "Power Graphics Programming", Michael Abrash
  503. // **************************************************************************
  504.  
  505. void line(int x0, int y0, int x1, int y1, int color)
  506.     {
  507.     int deltaX, deltaY;
  508.     int temp;
  509.  
  510.     if (y0>y1)
  511.         {
  512.         temp=y0;
  513.         y0=y1;
  514.         y1=temp;
  515.         temp=x0;
  516.         x0=x1;
  517.         x1=temp;
  518.         }
  519.  
  520.     deltaX=x1-x0;
  521.     deltaY=y1-y0;
  522.  
  523.     if (deltaX > 0)
  524.         {
  525.         if (deltaX>deltaY)
  526.             Octant0(x0,y0,deltaX,deltaY,1,color);
  527.         else
  528.             Octant1(x0,y0,deltaX,deltaY,1,color);
  529.         }
  530.     else
  531.         {
  532.         deltaX= -deltaX;
  533.         if (deltaX > deltaY)
  534.             Octant0(x0,y0,deltaX,deltaY,-1,color);
  535.         else
  536.             Octant1(x0,y0,deltaX,deltaY,-1,color);
  537.         }
  538.     }
  539.  
  540. // **************************************************************************
  541. // getimage() grabs the pixel values in the rectangle marked by (x0,y0) on
  542. // the top left, and (x1,y1) on the bottom right. The data is placed in buff.
  543. //
  544. // NOTE: This function needs translating into assembler
  545. // **************************************************************************
  546.  
  547. void getimage(int x0, int y0, int x1, int y1, char far *buff)
  548.     {
  549.     int i;
  550.     int deltaY=(y1-y0);
  551.     int xdim=(x1-x0);
  552.  
  553.     for (i=0;i<=deltaY;i++)
  554.         {
  555.         _fmemcpy((void *)&buff[i*xdim],xy_to_ptr(x0,(y0+i)),xdim);
  556.         }
  557.     }
  558.  
  559. // **************************************************************************
  560. // putimage() copies the data in *buff to a rectangular area of the screen
  561. // marked by (x0,y0) on the top left, and (x1,y1) on the bottom right.
  562. //
  563. // NOTE: This function needs translating into assembler
  564. // **************************************************************************
  565.  
  566. void putimage(int x0, int y0, int x1, int y1, char far *buff)
  567.     {
  568.     int i;
  569.     int deltaY=(y1-y0);
  570.     int xdim=(x1-x0);
  571.  
  572.     for (i=0;i<=deltaY;i++)
  573.         {
  574.         _fmemcpy(xy_to_ptr(x0,(y0+i)),(void *)&buff[i*xdim],xdim);
  575.         }
  576.     }
  577.  
  578. // *************************************************************************
  579. // copyimage copies a rectangular image bounded by (x0, y0) at top left, and
  580. // (x1, y1) at bottom right, to the video buffer at (putx, puty). The func-
  581. // tion is very fast, suitable for copying blocks of a virtual screen into
  582. // the physical screen for animation. It does no clipping, or checking for
  583. // the vertical blanking interval. If using it to copy from system ram to
  584. // the video buffer, make sure to pass a pointer to the buffer in src_buff,
  585. // and set GRAPH_SEG = to the video buffer before the call.
  586. // *************************************************************************
  587.  
  588. void copyimage(int x0, int y0, int x1, int y1, int putx, int puty,
  589.                void far *src_buf)
  590.     {
  591.     int deltaY=(y1-y0);
  592.     int xdim=(x1-x0);
  593.     asm    {
  594.         mov es, GRAPH_SEG           // establish GRAPH_SEG as destination seg
  595.         mov bx, 320                 // increment value to move down one line
  596.         mov ax, puty                // calculate the start of the first line
  597.         mul bx                      // for the destination
  598.         add ax, putx
  599.         mov di, ax
  600.         mov ax, y0                  // caluclate the start of the first line
  601.         mul bx                      // for the source
  602.         add ax, x0
  603.         push ds
  604.         lds si, src_buf
  605.         add si, ax
  606.         mov dx, deltaY              // set dx up as loop counter
  607.         cld                         // clear the direction flag
  608.         }
  609.     mainloop:                       // frame drawing loop
  610.     asm    {
  611.         mov cx, xdim                // cx == frame width in pixels
  612.         push si                     // save the line pointers
  613.         push di
  614.         shr cx, 1                   // optimized copy
  615.         rep movsw
  616.         rcl cx, 1
  617.         rep movsb
  618.         pop di                      // restore the line pointers
  619.         pop si
  620.         add di, 320                 // point to next line in source, dest
  621.         add si, 320
  622.         dec dx                      // adjust the loop counter
  623.         jnz mainloop
  624.         pop ds
  625.         }
  626.     }
  627.  
  628. // *************************************************************************
  629. // doSplitVerticalWipe causes the picture in pic_buf to be displayed by
  630. // wiping from left and right to the center. If called with a null pointer
  631. // it will clear the screen using palette register 0. Waits for the vertical
  632. // blanking interval, producing a smooth motion. This function really doesn't
  633. // need to be done in assembler, as the vbi test is the limiting factor (see
  634. // below)
  635. // *************************************************************************
  636.  
  637. void  doSplitVerticalWipe(void far *pic_buf)
  638.     {
  639.     unsigned leftx = 0;
  640.     unsigned rightx = 319;
  641.     unsigned run_y;                    // counts rows
  642.     char far *lsrc_ptr;                // pointer to left column in source
  643.     char far *ldst_ptr;                // pointer to left column in dest
  644.     char far *rsrc_ptr;                // pointer to right column in source
  645.     char far *rdst_ptr;                // pointer to right column in dest
  646.  
  647.     if (pic_buf != NULL)
  648.         {
  649.         while (rightx > leftx)
  650.             {
  651.             ldst_ptr = (char far *)xy_to_ptr(leftx, 0);
  652.             lsrc_ptr = (char far *)pic_buf+leftx;
  653.             rdst_ptr = (char far *)xy_to_ptr(rightx, 0);
  654.             rsrc_ptr = (char far *)pic_buf+rightx;
  655.             wait_vbi();
  656.             for (run_y = 0; run_y < 200; run_y++)
  657.                 {
  658.                 *ldst_ptr = *lsrc_ptr;
  659.                 *rdst_ptr = *rsrc_ptr;
  660.                 ldst_ptr += 320;
  661.                 lsrc_ptr += 320;
  662.                 rdst_ptr += 320;
  663.                 rsrc_ptr += 320;
  664.                 }
  665.             leftx++;
  666.             rightx--;
  667.             }
  668.         }
  669.     else
  670.         {
  671.         while (rightx > leftx)
  672.             {
  673.             ldst_ptr = (char far *)xy_to_ptr(leftx, 0);
  674.             rdst_ptr = (char far *)xy_to_ptr(rightx, 0);
  675.             wait_vbi();
  676.             for (run_y = 0; run_y < 200; run_y++)
  677.                 {
  678.                 *ldst_ptr = 0;
  679.                 *rdst_ptr = 0;
  680.                 ldst_ptr += 320;
  681.                 rdst_ptr += 320;
  682.                 }
  683.             leftx++;
  684.             rightx--;
  685.             }
  686.         }
  687.     }
  688.  
  689. // **************************************************************************
  690. // doSplitHorizWipe displays the picture in pic_buf by wiping it down from
  691. // top and bottom. If it's called with a null pointer it clears the screen
  692. // with palette register 0. Waits for vertical blanking interval, producing
  693. // a smooth wipe. This function really didn't need to be done in assembler.
  694. // I realized after I did it that the test for the vertical blanking interval
  695. // was the limiting factor, not the execution time. Lessons learned! <g>.
  696. //
  697. // This function moves the image data by copying lines to the top and bottom
  698. // of the screen alternately. The key to this process is the value in the
  699. // unsigned integer adjust. In the setup es:di and ds:si are set up to point
  700. // to the first line of the dest and source memory areas respectively. The
  701. // adjust variable is intialized to 64000, which, when added to the offset of
  702. // the first line, yields the offset of the last. Then adjust is decremented,
  703. // and subtracted from the offset of the last line to get the offset of the
  704. // second, and so on. The value of adjust is not used directly, but is loaded
  705. // into the bx register. Keep an eye on si and di, as they are saved and
  706. // restored quite often in all of these dissolve functions.
  707. // **************************************************************************
  708.  
  709. void  doSplitHorizWipe(void far *pic_buf)
  710.     {
  711.     unsigned adjust = 64000U;    // used to adjust di and si
  712.     asm {
  713.         mov dx, input_status_1   // used to test for vbi later
  714.         mov cx, 200              // line counter
  715.         mov bx, adjust           // bx stores adjust value
  716.         mov es, GRAPH_SEG        // else get video segment into es
  717.         xor di, di               // zero out the offset
  718.         push ds
  719.         lds si, pic_buf          // get pic_buf into es:di
  720.         mov ax, ds               // check for a null pointer
  721.         cmp ax,0
  722.         je clearscr              // if it's null clear the screen
  723.         cld                      // clear the direction flag
  724.         }
  725.     mainloop1:                   // outer line loop
  726.     asm {
  727.         push cx                  // save loop counter
  728.         mov cx, 160              // move 160 words
  729.         push si                  // save offsets
  730.         push di
  731.         }
  732.     test_11:                     // these lines wait for vbi
  733.     asm    {
  734.         in al, dx                // first test, out of vbi
  735.         test al,0x8
  736.         jnz test_11
  737.         }
  738.     test_12:
  739.     asm    {
  740.         in al, dx                // second test, in vbi
  741.         test al,0x8
  742.         jz test_12
  743.  
  744.         rep movsw                // copy words to video segment
  745.         pop di                   // restore the original offsets
  746.         pop si
  747.         sub bx, 320              // take one line off of bx
  748.         add si, bx               // add it to the offsets
  749.         add di, bx
  750.         mov cx, 160              // move 160 more words
  751.         push si                  // save the offsets
  752.         push di
  753.         rep movsw                // copy the data to video seg
  754.         pop di                   // restore the offsets
  755.         pop si
  756.         sub bx, 320              // take 1 line off of bx
  757.         sub si, bx               // subtract it from the offsets
  758.         sub di, bx
  759.         pop cx                   // restore the outer loop counter
  760.         loop mainloop1           // do next two lines
  761.         jmp done                 // skip the next part
  762.         }
  763.     clearscr:
  764.     asm cld;                     // clear the direction flag
  765.  
  766.     mainloop2:
  767.     asm {
  768.         push cx                  // save the loop counter
  769.         mov cx, 160              // move 160 words
  770.         push di                  // save the offset
  771.         }
  772.     test_21:                     // these lines test for vbi
  773.     asm    {
  774.         in al, dx                // first test, out of vbi
  775.         test al,0x8
  776.         jnz test_21
  777.         }
  778.     test_22:
  779.     asm    {
  780.         in al, dx                // second test, in vbi
  781.         test al,0x8
  782.         jz test_22
  783.         xor ax, ax               // clear ax, value to be stored==0
  784.         rep stosw                // clear the line
  785.         pop di                   // restore the offset
  786.         sub bx, 320              // take one line from bx
  787.         add di, bx               // add it to the offset
  788.         mov cx, 160              // mov 160 more words
  789.         push di                  // save the offset
  790.         rep stosw                // copy the data to video buff
  791.         pop di                   // restore the offset
  792.         sub bx, 320              // take one line from bx
  793.         sub di, bx               // subtract it from the offset
  794.         pop cx                   // restore the loop counter
  795.         loop mainloop2
  796.         }
  797.     done:
  798.     asm pop ds;
  799.     }
  800.  
  801. // **************************************************************************
  802. // doSlideVerticalWipe causes the image in pic_buf to be displayed by sliding
  803. // it in from both sides toward the center. Does not check pic_buff for a non
  804. // null address. Waits for vertical blanking interval between writes, produc-
  805. // ing a smooth image motion.
  806. //
  807. // This function basically captures frames from the left and right sides of
  808. // the source image and displays them in the video buffer so that the image
  809. // appears to be sliding onto the screen. This is done by starting with very
  810. // narrow slices, which are grabbed from the center of the source, and disp-
  811. // layed at the outside edges of the screen. As the slices get wider they re-
  812. // main rooted to the edges of the screen, so that they appear to slide into
  813. // the center. The outer loop iterates 160 times, or half the screen width.
  814. // On each iteration the width of the frame (i_wid) is increased by one, and
  815. // es:di, ds:si point to the top left corner of the source frame.
  816. // **************************************************************************
  817.  
  818. void doSlideVerticalWipe(void far *pic_buf)
  819.     {
  820.     int i_wid, x0, putx;
  821.     char ctrl;                   // controls branching
  822.  
  823.     asm    {
  824.         mov i_wid, 0             // zero out the outer loop counter
  825.         push ds                  // save the data segment
  826.         mov es, GRAPH_SEG        // get the video segment into es
  827.         }
  828.     lefthalf:
  829.     asm {
  830.         mov ax, 160              // get center line into ax
  831.         sub ax, i_wid            // i_wid is the offset from center
  832.         mov x0, ax               // x0 is the top left of the source block
  833.         mov putx, 0              // putx is the top left of the dest block
  834.         mov ctrl, 0
  835.         jmp doframe              // display the frame
  836.         }
  837.  
  838.     righthalf:
  839.     asm {
  840.         mov ax, 160              // mostly same as above except for
  841.         mov x0, ax               // right side
  842.         mov ax, 319
  843.         sub ax, i_wid
  844.         mov putx, ax
  845.         mov ctrl, 1
  846.         jmp doframe
  847.         }
  848.     checkloop:
  849.     asm {
  850.         inc i_wid
  851.         cmp i_wid, 160           // have 160 iterations
  852.         jna lefthalf
  853.         pop ds                   // restore data segment
  854.         }
  855.     return;                      // ** exit point **
  856.  
  857.     doframe:
  858.     asm {
  859.         mov di, putx             // di == top left corner of destination
  860.         mov dx, input_status_1   // used to test for vbi below
  861.         lds si, pic_buf          // get picture pointe into ds:si
  862.         add si, x0               // set si == top left corner of source block
  863.         }
  864.     test_1:                      // these lines test for the vbi
  865.     asm    {
  866.         in al, dx                // first test, out of vbi
  867.         test al,0x8
  868.         jnz test_1
  869.         }
  870.     test_2:
  871.     asm    {
  872.         in al, dx                // second test, in vbi
  873.         test al,0x8
  874.         jz test_2
  875.         mov dx, 200              // set dx up as loop counter
  876.         cld                      // clear the direction flag
  877.         }
  878.     mainloop:                    // frame drawing loop
  879.     asm    {
  880.         mov cx, i_wid            // i_wid is equal to the block width
  881.         push si                  // save the offsets
  882.         push di
  883.         shr cx, 1                // optimized copy technique, cx==number of
  884.         rep movsw                // number of bytes/2
  885.         rcl cx, 1                // now, if cx was odd, cx == 1, else cx ==0
  886.         rep movsb                // catches any odd byte  (thanks to Gus S.)
  887.         pop di                   // restore the offsets
  888.         pop si
  889.         add di, 320              // point to the next line
  890.         add si, 320
  891.         dec dx                   // adjust the outer loop counter
  892.         jnz mainloop
  893.  
  894.         cmp ctrl, 0              // if last copy was lefthalf do righthalf
  895.         je righthalf
  896.         jmp checkloop
  897.         }
  898.     }
  899.  
  900. // **************************************************************************
  901. // doSlideHorizWipe operates almost exactly like doSlideVerticalWipe above,
  902. // except that the image slides in from top and bottom instead of from left
  903. // and right. Like the other wipes it uses the wipe to clear the screen if
  904. // called with pic_buf == NULL.
  905. //
  906. // This function operates almost exactly like the vertical version directly
  907. // above.
  908. // **************************************************************************
  909.  
  910. void  doSlideHorizWipe(void far *pic_buf)
  911.     {
  912.     int i_wid, y0, puty;
  913.     char ctrl;                   // controls branching
  914.  
  915.     asm    {
  916.         mov i_wid, 1             // zero out the outer loop counter
  917.         push ds                  // save the data segment
  918.         mov es, GRAPH_SEG        // get the video segment into es
  919.         }
  920.     tophalf:
  921.     asm {
  922.         mov ax, 100              // get center line into ax
  923.         sub ax, i_wid            // i_wid is the offset from center
  924.         mov bx, 320
  925.         mul bx
  926.         mov y0, ax               // x0 is the top left of the source block
  927.         mov puty, 0              // putx is the top left of the dest block
  928.         mov ctrl, 0
  929.         jmp doframe              // display the frame
  930.         }
  931.  
  932.     bottomhalf:
  933.     asm {
  934.         mov ax, 99               // mostly same as above except for
  935.         mov bx, 320
  936.         mul bx
  937.         mov y0, ax               // right side
  938.         mov ax, 199
  939.         sub ax, i_wid
  940.         mul bx
  941.         mov puty, ax
  942.         mov ctrl, 1
  943.         jmp doframe
  944.         }
  945.     checkloop:
  946.     asm {
  947.         inc i_wid
  948.         cmp i_wid, 100           // have 160 iterations
  949.         jna tophalf
  950.         pop ds                   // restore data segment
  951.         }
  952.     return;                      // ** exit point **
  953.  
  954.     doframe:
  955.     asm {
  956.         mov di, puty             // di == top left corner of destination
  957.         mov dx, input_status_1   // used to test for vbi below
  958.         lds si, pic_buf          // get picture pointe into ds:si
  959.         add si, y0               // set si == top left corner of source block
  960.         }
  961.     test_1:                      // these lines test for the vbi
  962.     asm    {
  963.         in al, dx                // first test, out of vbi
  964.         test al,0x8
  965.         jnz test_1
  966.         }
  967.     test_2:
  968.     asm    {
  969.         in al, dx                // second test, in vbi
  970.         test al,0x8
  971.         jz test_2
  972.         mov dx, i_wid            // set dx up as loop counter
  973.         cld                      // clear the direction flag
  974.         }
  975.     mainloop:                    // frame drawing loop
  976.     asm    {
  977.         mov cx, 160              // i_wid is equal to the block width
  978.         push si                  // save the offsets
  979.         push di
  980.         rep movsw                // number of bytes/2
  981.         pop di                   // restore the offsets
  982.         pop si
  983.         add di, 320              // point to the next line
  984.         add si, 320
  985.         dec dx                   // adjust the outer loop counter
  986.         jnz mainloop
  987.  
  988.         cmp ctrl, 0              // if last copy was lefthalf do righthalf
  989.         je bottomhalf
  990.         jmp checkloop
  991.         }
  992.     }
  993.  
  994. // *************************************************************************
  995. // doVerticalDissolve causes the image stored in pic_buf to be displayed by
  996. // fading in multiple vertical slices. It is the vertical equivalent of the
  997. // doHorizDissolve function. When called with a null pointer it clears the
  998. // screen.
  999. //
  1000. // The function moves the image data to the screen by iterating through
  1001. // 16 vertical slices. On each iteration two lines are drawn, at an equal
  1002. // distance on either side of the center mark for that section. The outer-
  1003. // most loop counts the lines; it takes 10 iterations to fill one slice. The
  1004. // innermost loop cycles through the 16 slices. So, the first slice gets two
  1005. // lines, the second gets two, on up to the 16th, and then the first gets
  1006. // two more, and so on. Keep an eye on si and di.
  1007. // *************************************************************************
  1008.  
  1009. void  doVerticalDissolve(void far *pic_buf)
  1010.     {
  1011.     int base_row;                //  base_row stores the line offset from x
  1012.     asm {
  1013.         mov es, GRAPH_SEG        // get the video segment into es
  1014.         mov base_row, 0          // start out drawing on the x pixel
  1015.         mov cx, 11               // outer loop, 11 pixels to each side of
  1016.         cld                      // the x pixel (in si and di) will be drawn
  1017.         push ds                  // save the ds register value
  1018.         lds si, pic_buf          // get the picture pointer into ds:si
  1019.         mov ax, ds               // check for a NULL pointer and jmp to
  1020.         cmp ax, 0                // clearscr if found
  1021.         je clearscr
  1022.         }
  1023.     mainloop:
  1024.     asm {
  1025.         push cx                  // save the outer loop counter
  1026.         push si                  // save original offset to byte 0 of pic
  1027.         mov cx, 16               // process 16 vertical slices
  1028.         add si, 9                // first x mark is on 9,0
  1029.         mov di, 9
  1030.         }
  1031.     drawloop:
  1032.     asm {
  1033.         push cx                  // save the inner loop counter
  1034.         push si                  // and the x mark, source and dest
  1035.         push di
  1036.         add di, base_row         // add in the offset from x for first line
  1037.         add si, base_row
  1038.         mov cx, 200              // plot 200 pixels
  1039.         }
  1040.     lineloop1:                   // this loop draws a vertical line
  1041.     asm {
  1042.         movsb                    // move one byte
  1043.         add si, 319              // move to next row
  1044.         add di, 319
  1045.         loop lineloop1           // do another
  1046.  
  1047.         pop di                   // restore the starting points
  1048.         pop si
  1049.         push si                  // save them again
  1050.         push di
  1051.         sub di, base_row         // drawing on the other side this time
  1052.         sub si, base_row
  1053.         mov cx, 200              // plot 200 pixels
  1054.         }
  1055.     lineloop2:
  1056.     asm {
  1057.         movsb                    // same as above
  1058.         add si, 319
  1059.         add di, 319
  1060.         loop lineloop2
  1061.  
  1062.         pop di                   // restore the starting point
  1063.         pop si
  1064.         pop cx                   // restore the inner loop counter
  1065.         add si, 20               // adjust pointer to the next slice
  1066.         add di, 20
  1067.         loop drawloop            // process it
  1068.         inc base_row             // increment the drawing offset
  1069.         pop si                   // restore the offset to byte 0 of pic
  1070.         pop cx                   // restore the outer loop counter
  1071.         loop mainloop            // do it all again
  1072.         jmp done
  1073.         }
  1074.     clearscr:                    // this block functions exactly as the
  1075.     asm {                        // previous one but clears the screen using
  1076.         push cx                  // palette register 0
  1077.         mov cx, 16
  1078.         mov di, 9
  1079.         }
  1080.     drawloop2:
  1081.     asm {
  1082.         push cx
  1083.         push di
  1084.         add di, base_row
  1085.         xor ax, ax
  1086.         mov cx, 200
  1087.         }
  1088.     lineloop21:
  1089.     asm {
  1090.         stosb
  1091.         add di, 319
  1092.         loop lineloop21
  1093.  
  1094.         pop di
  1095.         push di
  1096.         sub di, base_row
  1097.         xor ax, ax
  1098.         mov cx, 200
  1099.         }
  1100.     lineloop22:
  1101.     asm {
  1102.         stosb
  1103.         add di, 319
  1104.         loop lineloop22
  1105.         pop di
  1106.         pop cx
  1107.         add di, 20
  1108.         loop drawloop2
  1109.         inc base_row
  1110.         pop cx
  1111.         loop clearscr
  1112.         }
  1113.     done:
  1114.     asm pop ds;                  // restore the data segment
  1115.     }
  1116.  
  1117. // **************************************************************************
  1118. // doHorizDissolve causes the image in pic_buf to be displayed by dissolving
  1119. // it in in 10 horizontal bands. If called with pic_buf==NULL it clears the
  1120. // screen by the same method.
  1121. //
  1122. // This function processes the data much like the Vertcal Dissolve funtion
  1123. // above. The screen in this case is divided into 10 horizontal slices. The
  1124. // center line starting points of these slices begin at 2880 bytes into the
  1125. // video buffer, and every 6400 bytes after that. Like the function above it
  1126. // cycles through the slices drawing two lines at each, progressively further
  1127. // from the center line with each iteration of the outer loop. Like the func-
  1128. // tion above, you have to keep a carefull eye on di and si to understand it.
  1129. // **************************************************************************
  1130.  
  1131. void  doHorizDissolve(void far *pic_buf)
  1132.     {
  1133.     int base_line;
  1134.     asm {
  1135.         mov base_line, 0          // base_line is an offset from each line
  1136.         mov es, GRAPH_SEG         // get video segment into es
  1137.         mov bx, 320               // bx * base_line == adjust value for si,di
  1138.         mov cx, 20                // outer loop 20 iterations
  1139.         cld                       // clear the direction flag
  1140.         push ds                   // save the ds register value
  1141.         lds si, pic_buf           // get pic_buf into ds:si
  1142.         mov ax, ds                // if pic_buf == NULL jump to clearscr
  1143.         cmp ax, 0
  1144.         je clearscr
  1145.         }
  1146.     mainloop1:                    // main drawing loop, 20 iterations...
  1147.     asm {                         // the number of offset lines to draw
  1148.         push cx                   // save the counter
  1149.         mov cx, 10                // inner loop, 10 iterations, draws lines
  1150.         push si                   // save the offset of the pic_buf pointer
  1151.         add si, 60480             // 60480, address of first line processed
  1152.         mov di, 60480
  1153.         mov dx, input_status_1    // used below to test for vbi
  1154.         }
  1155.     test_11:                      // these lines test for the vbi
  1156.     asm    {
  1157.         in al, dx                 // first test, out of vbi
  1158.         test al,0x8
  1159.         jnz test_11
  1160.         }
  1161.     test_12:
  1162.     asm    {
  1163.         in al, dx                 // second test, in vbi
  1164.         test al,0x8
  1165.         jz test_12
  1166.         }
  1167.     drawloop1:                    // drawloop processes the 10 base lines,
  1168.     asm {                         // drawing 2 lines at offset ax from base
  1169.         push cx                   // save the counter
  1170.         push si                   // save the offset to the current base
  1171.         push di
  1172.         mov ax, base_line         // calculate the pointer offset from base
  1173.         mul bx                    // by multiplying base_line * 320
  1174.         sub si, ax                // subtract the offset from source and
  1175.         sub di, ax                // dest base pointers, and
  1176.         mov cx, 160               // draw the first line
  1177.         rep movsw
  1178.         pop di                    // restore the base pointers
  1179.         pop si
  1180.         push si                   // save em again
  1181.         push di
  1182.         add si, ax                // add the offset to the source and dest
  1183.         add di, ax                // base pointers and
  1184.         mov cx, 160               // draw the second line
  1185.         rep movsw
  1186.         pop di                    // restore the base pointers
  1187.         pop si
  1188.         pop cx                    // restore the inner loop counter
  1189.         sub si, 6400              // adjust base pointers to point to the
  1190.         sub di, 6400              // next base, 20 lines up the screen
  1191.         loop drawloop1            // process the next section
  1192.         inc base_line             // increment the base offset factor
  1193.         pop si                    // restore the original pic_buf offset
  1194.         pop cx                    // restore the outer loop counter
  1195.         loop mainloop1            // do it all over again
  1196.         jmp done                  // finished
  1197.         }
  1198.     clearscr:                     // this section executes if pic_buf==NULL
  1199.     asm {
  1200.         push cx                   // save the outer loop counter
  1201.         mov cx, 10
  1202.         mov di, 60480             // we can ignore ds:si since no source
  1203.         mov dx, input_status_1    // used to test for vbi below
  1204.         }
  1205.     test_21:                      // these lines test for the vbi
  1206.     asm    {
  1207.         in al, dx                 // first test, out of vbi
  1208.         test al,0x8
  1209.         jnz test_21
  1210.         }
  1211.     test_22:
  1212.     asm    {
  1213.         in al, dx                 // second test, in vbi
  1214.         test al,0x8
  1215.         jz test_22
  1216.         }
  1217.     drawloop2:
  1218.     asm {
  1219.         push cx                  // save the inner loop counter
  1220.         push di                  // save the base offset
  1221.         mov ax, base_line        // calculate the drawing offset from base
  1222.         mul bx
  1223.         sub di, ax               // subtract the offset from the base pointer
  1224.         push ax                  // save the offset
  1225.         xor ax, ax               // clear ax for use in stosw instruction
  1226.         mov cx, 160
  1227.         rep stosw                // clear the first line
  1228.         pop ax                   // restore the offset
  1229.         pop di                   // restore the base pointer
  1230.         push di                  // save it again
  1231.         add di, ax               // add the offset to the base pointer
  1232.         xor ax, ax               // clear ax for use in stosw instruction
  1233.         mov cx, 160
  1234.         rep stosw                // clear the second line
  1235.         pop di                   // restore the base pointer
  1236.         pop cx                   // restore inner loop counter
  1237.         sub di, 6400             // adjust base pointer to 20 lines up screen
  1238.         loop drawloop2           // process the next section
  1239.         inc base_line            // increment the offset factor
  1240.         pop cx                   // restore the outer loop counter
  1241.         loop clearscr
  1242.         }
  1243.     done:                        // finished
  1244.     asm pop ds;                  // restore ds value
  1245.     }
  1246.  
  1247.  
  1248.  
  1249. void  doSparkleDissolve(void far *pic_buf)
  1250.     {
  1251.     }
  1252.  
  1253.  
  1254.  
  1255. // *************************************************************************
  1256. // member function definitions for class font, declared in images.hpp
  1257. // *************************************************************************
  1258.  
  1259. // *************************************************************************
  1260. // constructor takes a char * filepath. It opens the fontfile, gets the
  1261. // font header into the member structure font_hdr, then allocates memory
  1262. // and reads the font data into it. Errors cause the constructor set the
  1263. // font status to 0, then return.  The status can be checked via the
  1264. // font::getstatus() method.
  1265. // *************************************************************************
  1266.  
  1267. font::font(char *f_spec)
  1268.     {
  1269.     int handle;
  1270.     int readsize;
  1271.     int bytes_read=0;
  1272.     char cursor_size;
  1273.  
  1274.     if ((handle=open(f_spec,O_RDONLY|O_BINARY))==-1)
  1275.         {
  1276.         status = FileOpenErr;
  1277.         return;
  1278.         }
  1279.     bytes_read+=(read(handle,&f_hdr,sizeof(f_hdr)));
  1280.     bytes_read+=(read(handle,&width[0],sizeof(width)));
  1281.     cursor_size=(f_hdr.fram_wid*f_hdr.fram_hit);
  1282.     if (((void far *)cursor_mask=malloc(cursor_size)) ==NULL)
  1283.         {
  1284.         status = MemErr;
  1285.         return;
  1286.         }
  1287.     bytes_read+=(read(handle,(void far*)cursor_mask,cursor_size));
  1288.     readsize=(filelength(handle)-bytes_read);
  1289.     if (((void far *)font_ptr=malloc(readsize)) ==NULL)
  1290.         {
  1291.         free(cursor_mask);
  1292.         status = MemErr;
  1293.         return;
  1294.         }
  1295.     read(handle,(void far *)font_ptr,readsize);
  1296.     close(handle);
  1297.     fore_color=0;
  1298.     setstyle(0,15,1,opaque,4);
  1299.     status=1;
  1300. }
  1301.  
  1302. // *************************************************************************
  1303. // destructor disposes of the memory allocated to the font
  1304. // *************************************************************************
  1305.  
  1306. font::~font()
  1307.     {
  1308.     free(font_ptr);
  1309.     font_ptr=NULL;
  1310.     free(cursor_mask);
  1311.     cursor_mask=NULL;
  1312.     }
  1313.  
  1314. // *************************************************************************
  1315. // get_width() returns the proportional width in pixels of char c
  1316. // *************************************************************************
  1317.  
  1318. char font::get_width(char c)
  1319.     {
  1320.     if ((c>=f_hdr.ascii_first)&&(c<=f_hdr.ascii_last))
  1321.         return(width[c-f_hdr.ascii_first]);
  1322.     else
  1323.         return(0);
  1324.     }
  1325.  
  1326. // *************************************************************************
  1327. // put_char displays one bitmapped character at the passed x,y location
  1328. // *************************************************************************
  1329.  
  1330. void font::put_char(int x, int y, char c)
  1331.     {
  1332.     int j;
  1333.     int i;
  1334.     unsigned char src,dst;
  1335.     char far *p;
  1336.     int char_ofs;
  1337.     char_ofs=(c-f_hdr.ascii_first)*((f_hdr.fram_wid*f_hdr.fram_hit));
  1338.     (void far *)p=MK_FP(FP_SEG(font_ptr),FP_OFF(font_ptr)+char_ofs);
  1339.     for(j=0;j<f_hdr.fram_hit;j++)
  1340.         {
  1341.         for (i=0;i<f_hdr.fram_wid;i++)
  1342.             {
  1343.             src=p[(j*f_hdr.fram_wid)+i];
  1344.             if (src==f_hdr.f_color)
  1345.                 {
  1346.                 dst=fore_color;
  1347.                 writepixel(x+i,y+j,dst);
  1348.                 }
  1349.             else
  1350.                 {
  1351.                 if (see_thru==opaque)
  1352.                     {
  1353.                     dst=back_color;
  1354.                     writepixel(x+i,y+j,dst);
  1355.                     }
  1356.                 }
  1357.             }
  1358.         }
  1359.     }
  1360.  
  1361. // *************************************************************************
  1362. // returns the current foreground color setting for text output
  1363. // *************************************************************************
  1364.  
  1365. int font::getforecolor()
  1366.     {
  1367.     return(fore_color);
  1368.     }
  1369.  
  1370. // *************************************************************************
  1371. // returns the current background color setting for text output
  1372. // *************************************************************************
  1373.  
  1374. int font::getbackcolor()
  1375.     {
  1376.     return(back_color);
  1377.     }
  1378.  
  1379. // *************************************************************************
  1380. // call this function to set the style parameters for text output. f_grnd=
  1381. // foreground color, b_grnd=background color, char_tab=pixels between
  1382. // characters, opacity={trans,opaque}, when opacity=trans the background
  1383. // pixels in the font are ingored, when opacity=opaque the background pixels
  1384. // are set to the color value passed in b_grnd, space_wid=width in pixels
  1385. // of ascii character 32 (20h), the space character.
  1386. // *************************************************************************
  1387.  
  1388. void font::setstyle(int f_grnd,int b_grnd,short char_tab,
  1389.                     opacity o, char space_wid)
  1390.     {
  1391.     spacing=char_tab;
  1392.     see_thru=o;
  1393.     fore_color=f_grnd;
  1394.     back_color=b_grnd;
  1395.     width[32-f_hdr.ascii_first]=space_wid;
  1396.     }
  1397.  
  1398. // *************************************************************************
  1399. // ouput the string pointed to by str at the given x,y coordinate.
  1400. // *************************************************************************
  1401.  
  1402. void font::show(int x, int y, char *str)
  1403.     {
  1404.     int i;
  1405.     int j;
  1406.     for (j=0;str[j]!=0;j++);   // one line gets length of string
  1407.     for (i=0;i<j;i++)
  1408.         {
  1409.         put_char(x,y,str[i]);
  1410.         x += get_width(str[i])+spacing;
  1411.         }
  1412.     }
  1413.  
  1414. // *************************************************************************
  1415. // read a string from the keyboard, echo to screen at x,y. Reads until it
  1416. // encouters a carriage return <ascii 13>, or the string reaches width
  1417. // bytes in length, whichever occurs first. Displays a blinking cursor using
  1418. // the cursor mask loaded with the font. Backspace enabled.
  1419. // *************************************************************************
  1420.  
  1421. void font::readstr(int x, int y, char *str, char length, char mask)
  1422.     {
  1423.     char c='\0';                   // used in call to getfilteredkey()
  1424.     extnd scan=NO_EXT;             // ditto
  1425.     int cursor_x=x;                // cursor position/next letter position
  1426.     int cursor_y=y;                // ditto
  1427.     char cur_toggle=0;             // cursor display state
  1428.     unsigned int tick;             // last clock reading
  1429.     volatile unsigned int *clock=(unsigned int *)MK_FP(0x0040,0x006C);
  1430.     int str_len=0;                 // input string length
  1431.     int i,j;                       // generic counters
  1432.  
  1433.     str[str_len]='\0';
  1434.     while((c!=13)&&(str_len<length))
  1435.         {
  1436.         do
  1437.             {
  1438.             tick= *clock;
  1439.             while ((*clock<(tick+3))&&(!kbhit()));
  1440.             cur_toggle = !cur_toggle;
  1441.             for(j=0;j<f_hdr.fram_hit;j++)
  1442.                 {
  1443.                 for (i=0;i<(f_hdr.fram_wid-1);i++)
  1444.                     {
  1445.                     if ((cur_toggle==0)||(cursor_mask[(j*f_hdr.fram_wid+i)]==0))
  1446.                         writepixel(cursor_x+i,cursor_y+j,back_color);
  1447.                     else
  1448.                         writepixel(cursor_x+i,cursor_y+j,fore_color);
  1449.                     }
  1450.                 }
  1451.             } while ((!kbhit())||(cur_toggle!=0));
  1452.         if (getfilteredkey(mask,&c,&scan))
  1453.             {
  1454.             if ((c!=13)&&(c!=8)&&(c!=9)&&(c!=27))
  1455.                 {
  1456.                 str[str_len++]=c;
  1457.                 str[str_len]='\0';
  1458.                 put_char(cursor_x,cursor_y,c);
  1459.                 cursor_x+=(get_width(c)+spacing);
  1460.                 }
  1461.             else
  1462.                 {
  1463.                 if ((c==8)&&(str_len!=0))
  1464.                     {
  1465.                     cursor_x-=(get_width(str[str_len-1])+spacing);
  1466.                     str[--str_len]='\0';
  1467.                     }
  1468.                 }
  1469.             }
  1470.         }
  1471.     }
  1472.  
  1473. // **************************************************************************
  1474. // call installed() immediately after initializing an instance of class font.
  1475. // if it returns non-zero (true) the installation was successful. 0 indicates
  1476. // a file access or memory error during installation.
  1477. // **************************************************************************
  1478.  
  1479. int font::installed()
  1480.     {
  1481.     return(status);
  1482.     }
  1483.  
  1484. // **************************************************************************
  1485. // member function definitions for i_stack pointer stack class
  1486. //
  1487. // these don't have any specific place in a graphics module, except that they
  1488. // were going to be used in a window manager, and I was too lazy to make them
  1489. // a module to live in.
  1490. // **************************************************************************
  1491.  
  1492. // **************************************************************************
  1493. // constructor clears the pointer stack to NULL
  1494. // **************************************************************************
  1495.  
  1496. i_stack::i_stack()
  1497.     {
  1498.     int i;
  1499.  
  1500.     ptr_index=0;
  1501.     for (i=0;i<20;i++)
  1502.         {
  1503.         ptr_array[i]=NULL;
  1504.         }
  1505.     }
  1506.  
  1507. // **************************************************************************
  1508. // push a pointer on to the stack. Returns 0 if stack full, 1 if success
  1509. // **************************************************************************
  1510.  
  1511. char i_stack::push_ptr(void far *ptr)
  1512.     {
  1513.     if (ptr_index!=20)
  1514.         {
  1515.         ptr_array[ptr_index++]=ptr;
  1516.         return(1);
  1517.         }
  1518.     else
  1519.         {
  1520.         return(0);
  1521.         }
  1522.     }
  1523.  
  1524. // **************************************************************************
  1525. // pop a pointer from the stack. Returns NULL if stack empty.
  1526. // **************************************************************************
  1527.  
  1528. void far *i_stack::pop_ptr()
  1529.     {
  1530.     if (ptr_index!=0)
  1531.         return(ptr_array[--ptr_index]);
  1532.     else
  1533.         return(NULL);
  1534.     }
  1535.  
  1536. // **************************************************************************
  1537. // member function definitions for window class
  1538. // **************************************************************************
  1539.  
  1540. // **************************************************************************
  1541. // Constructor creates the window. See WIN.DOC for more information.
  1542. // **************************************************************************
  1543.  
  1544. win::win(int tlx, int tly, int xwid, int ywid, char far *bmap,
  1545.                char brdrwid, char shdwwid, char bgrnd, char border)
  1546.     {
  1547.     if (shdwwid==0)
  1548.         {
  1549.         shdwon=0;
  1550.         if ((backgrnd=new char[xwid*ywid])==NULL)
  1551.             {
  1552.             status = 0;
  1553.             return;
  1554.             }
  1555.         getimage(tlx,tly,tlx+xwid,tly+ywid,backgrnd);
  1556.         }
  1557.     else
  1558.         {
  1559.         shdwon=1;
  1560.         if ((backgrnd = new char[(xwid+shdwwid)*(ywid+shdwwid)])==NULL)
  1561.             {
  1562.             status=0;
  1563.             return;
  1564.             }
  1565.         getimage(tlx,tly,tlx+xwid+shdwwid,tly+ywid+shdwwid,backgrnd);
  1566.         barfill(tlx+xwid,tly+shdwwid,tlx+xwid+shdwwid,tly+ywid+shdwwid,0);
  1567.         barfill(tlx+shdwwid,tly+ywid,tlx+xwid,tly+ywid+shdwwid,0);
  1568.         }
  1569.     if (bmap==NULL)
  1570.         barfill(tlx,tly,tlx+xwid,tly+ywid,bgrnd);
  1571.     else
  1572.         putimage(tlx,tly,tlx+xwid,tly+ywid,bmap);
  1573.     if (brdrwid!=0)
  1574.         {
  1575.         if (brdrwid>1)
  1576.             {
  1577.             barfill(tlx,tly,tlx+xwid,tly+brdrwid,border);
  1578.             barfill(tlx+(xwid-brdrwid),tly,tlx+xwid,tly+ywid,border);
  1579.             barfill(tlx,tly+(ywid-brdrwid),tlx+xwid,tly+ywid,border);
  1580.             barfill(tlx,tly,tlx+brdrwid,tly+ywid,border);
  1581.             }
  1582.         else
  1583.             {
  1584.             line(tlx,tly,tlx+xwid,tly,border);
  1585.             line(tlx+xwid,tly,tlx+xwid,tly+ywid,border);
  1586.             line(tlx,tly+ywid,tlx+xwid,tly+ywid,border);
  1587.             line(tlx,tly,tlx,tly+ywid,border);
  1588.             }
  1589.         }
  1590.     origX=tlx;
  1591.     origY=tly;
  1592.     xsize=xwid;
  1593.     ysize=ywid;
  1594.     bdrwid=brdrwid;
  1595.     shdwid=shdwwid;
  1596.     b_grnd=bgrnd;
  1597.     brdr=border;
  1598.     status=1;
  1599.     return;
  1600.     }
  1601.  
  1602. win::~win()
  1603.     {
  1604.     if (shdwon)
  1605.         putimage(origX,origY,origX+xsize+shdwid,origY+ysize+shdwid,backgrnd);
  1606.     else
  1607.         putimage(origX,origY,origX+xsize,origY+ysize,backgrnd);
  1608.     delete(backgrnd);
  1609.     return;
  1610.     }
  1611.  
  1612. // **************************************************************************
  1613. // member function defintions for pcx class
  1614. // **************************************************************************
  1615.  
  1616. // **************************************************************************
  1617. // constructor opens the file as binary, readonly. It reads the dac palette
  1618. // into the member p_rec structure palette, corrects it for shift, sets sev-
  1619. // eral status variables, and closes the file. On error it sets pcx.status to
  1620. // Failed, and reports the error in the images module error record imag_err.
  1621. // **************************************************************************
  1622.  
  1623. pcx::pcx(char *fspec)
  1624.     {
  1625.     char check_pal;
  1626.     int i,j;
  1627.     FILE *filptr;
  1628.  
  1629.     status = NoErr;
  1630.  
  1631.     if ((filptr = fopen(fspec,"rb"))==NULL)
  1632.         {
  1633.         status = FileOpenErr;
  1634.         return;
  1635.         }
  1636.     if (fseek(filptr,-769L,SEEK_END) != 0)
  1637.         {
  1638.         status= FileReadErr;
  1639.         fclose(filptr);
  1640.         return;
  1641.         }
  1642.     fread(&check_pal,1,1,filptr);
  1643.  
  1644.     // check for 256 color PCX palette tag 0x0C at filelength-769
  1645.  
  1646.     if (check_pal!=0x0C)
  1647.         {
  1648.         status = FileFormatErr;
  1649.         fclose(filptr);
  1650.         return;
  1651.         }
  1652.  
  1653.     // read in the palette and store in class member data palette
  1654.  
  1655.     if (fread(palette,1,768,filptr) != 768)
  1656.         {
  1657.         status = FileReadErr;
  1658.         fclose(filptr);
  1659.         return;
  1660.         }
  1661.  
  1662.     // shift the palette values right by two bits (pcx specific detail)
  1663.  
  1664.     for (i=0;i<256;i++)
  1665.         {
  1666.         for (j=0;j<3;j++)
  1667.             {
  1668.             palette[i][j]=palette[i][j]>>2;
  1669.             }
  1670.         }
  1671.  
  1672.     // leave the file pointer on the first byte of image data
  1673.  
  1674.     if (fseek(filptr,128,SEEK_SET) != 0)
  1675.         {
  1676.         status = FileReadErr;
  1677.         fclose(filptr);
  1678.         return;
  1679.         }
  1680.     fclose(filptr);
  1681.     buffer=NULL;                       // pcx:image.buffer
  1682.     for (j=0;fspec[j]!=0;j++);         // these two lines copy the path to
  1683.     memcpy(fpath,fspec,j+1);           // to storage in the object data
  1684.     in_ram = 0;                        // pcx.in_ram
  1685.     packed = 0;                        // pcx.packed
  1686.     return;
  1687.     }
  1688.  
  1689. // **************************************************************************
  1690. // unpacktoram unpacks the rle encoded into the buffer pointed to by dest.
  1691. // No size checking is performed on the buffer. The unpacking process cont-
  1692. // inues until num_bytes have been moved to dest. The function checks the
  1693. // state of the in_ram member variable. If the image is not in memory it is
  1694. // unpacked from the disk file. If the image is in memory in compressed mode
  1695. // it is unpacked from memory. If the image is in memory, but is already
  1696. // uncompressed the function returns UnknownErr.
  1697. // **************************************************************************
  1698.  
  1699. char pcx::unpacktoram(char far *dest, unsigned int num_bytes)
  1700.     {
  1701.     unsigned int bytes=0;           // counts unpacked bytes
  1702.     char    c;                      // byte being processed
  1703.     int     runlen;                 // length of packet
  1704.     unsigned int src_cntr = 0;      // counts through ram buffer if any
  1705.     char far *streambuf;
  1706.     FILE *filptr;
  1707.  
  1708.     if (!in_ram)
  1709.         {
  1710.         if ((filptr=fopen(fpath,"rb"))==NULL)
  1711.             return(FileOpenErr);
  1712.         if ((streambuf=new char[5000]) != NULL)
  1713.             {
  1714.             setbuf(filptr,streambuf);
  1715.             }
  1716.         if (fseek(filptr,128L,SEEK_SET) != 0)
  1717.             {
  1718.             fclose(filptr);
  1719.             if (streambuf != NULL)
  1720.                 delete(streambuf);
  1721.             return(FileReadErr);
  1722.             }
  1723.         do
  1724.             {
  1725.             c=fgetc(filptr);
  1726.             if ((c & 0xc0) == 0xc0)
  1727.                 {
  1728.                 runlen = (c & 0x3f);
  1729.                 c=fgetc(filptr);
  1730.                 while(runlen--) (dest[bytes++]=c);
  1731.                 }
  1732.             else
  1733.                 dest[bytes++]=c;
  1734.             } while (bytes<num_bytes);
  1735.         fclose(filptr);
  1736.         if (streambuf!=NULL)
  1737.             delete(streambuf);
  1738.         }
  1739.     else
  1740.         {
  1741.         if (!packed)
  1742.             return(UnknownErr);
  1743.         else
  1744.             {
  1745.             do
  1746.                 {
  1747.                 c=buffer[src_cntr++];
  1748.                 if ((c & 0xc0) == 0xc0)
  1749.                     {
  1750.                     runlen = (c & 0x3f);
  1751.                     c=buffer[src_cntr++];
  1752.                     while(runlen--) (dest[bytes++]=c);
  1753.                     }
  1754.                 else
  1755.                     dest[bytes++]=c;
  1756.                 } while (bytes<num_bytes);
  1757.             }
  1758.         }
  1759.     return(NoErr);
  1760.     }
  1761.  
  1762.  
  1763. // **************************************************************************
  1764. // the load() member function reads the pcx file into a memory buffer. The
  1765. // pointer to the buffer and the buffer size are internal to the class, and
  1766. // do not need to be taken into account by the programmer. The data is loaded
  1767. // based on the value of method. A set of three constants is defined for this
  1768. // value; Packed, Unpacked, and Bestfit. If method = packed the data will be
  1769. // read into the memory buffer in compressed PCX format, but the palette and
  1770. // header data will be stripped. If method = unpacked the data is uncompress-
  1771. // to memory using the unpacktoram() function. In either case, if there is
  1772. // not sufficient memory, the function returns MemErr. If method = Bestfit
  1773. // the function will unpack the data is possible, or load it packed if not,
  1774. // and finally returns MemErr if neither method can be used. If successfull
  1775. // the function sets internal switches so that other pcx member functions
  1776. // will know that the image data is already loaded, and in what form it has
  1777. // been loaded.
  1778. // **************************************************************************
  1779.  
  1780. char pcx::load(char method)
  1781.     {
  1782.     unsigned readsize;
  1783.     FILE *filptr;
  1784.  
  1785.     // make sure the image isn't already loaded
  1786.  
  1787.     if (!in_ram)
  1788.         {
  1789.         if (method == Bestfit)
  1790.             {
  1791.  
  1792.             // if enough ram for the image load unpacked
  1793.  
  1794.             if (coreleft() >= 64000U)
  1795.                 {
  1796.                 method = Unpacked;
  1797.                 }
  1798.             else
  1799.  
  1800.             // if not enough ram open the file, compare it's size to the
  1801.             // available memory, and load it packed if there's enough room
  1802.             // or return a MemErr if there isn't.
  1803.  
  1804.                 {
  1805.                 if ((filptr=fopen(fpath,"rb"))==NULL)
  1806.                     {
  1807.                     return(FileOpenErr);
  1808.                     }
  1809.                 readsize = filelength(fileno(filptr))-(128+769);
  1810.                 fclose(filptr);
  1811.                 if (coreleft() >= readsize)
  1812.                     method = Packed;
  1813.                 else
  1814.                     return(MemErr);
  1815.                 }
  1816.             }
  1817.  
  1818.         // if method = packed then allocate a buffer the size of the image
  1819.         // file with the header and palette data stripped out. Zero the
  1820.         // buffer, then read the packed data into it. Finally, set in_ram
  1821.         // and packed = 1 (pcx class member data used by display() member
  1822.         // function)
  1823.  
  1824.         if (method == Packed)
  1825.             {
  1826.             if ((filptr=fopen(fpath,"rb"))==NULL)
  1827.                 return(FileOpenErr);
  1828.             readsize = filelength(fileno(filptr))-(128+769);
  1829.             if ((buffer = new char[readsize]) == NULL)
  1830.                 {
  1831.                 fclose(filptr);
  1832.                 return(MemErr);
  1833.                 }
  1834.             _fmemset(buffer,0,readsize);
  1835.             if (fseek(filptr, 128L, SEEK_SET) != 0)
  1836.                 {
  1837.                 fclose(filptr);
  1838.                 delete(buffer);
  1839.                 return(FileReadErr);
  1840.                 }
  1841.             if (fread(buffer, 1, readsize, filptr) != readsize)
  1842.                 {
  1843.                 fclose(filptr);
  1844.                 delete(buffer);
  1845.                 return(FileReadErr);
  1846.                 }
  1847.             fclose(filptr);
  1848.             in_ram = 1;
  1849.             packed = 1;
  1850.             }
  1851.         else
  1852.  
  1853.         // if method = Unpacked then allocate a 64000 byte buffer, and
  1854.         // unpack the data into it.
  1855.  
  1856.             {
  1857.             if ((buffer = new char[64000U]) == NULL)
  1858.                 return(MemErr);
  1859.             _fmemset(buffer,0,64000U);
  1860.             if(unpacktoram(buffer,64000U) != NoErr)
  1861.                 {
  1862.                 delete(buffer);
  1863.                 in_ram = 0;
  1864.                 return(SecondaryErr);
  1865.                 }
  1866.             else
  1867.                 {
  1868.                 in_ram = 1;
  1869.                 packed = 0;
  1870.                 }
  1871.             }
  1872.         }
  1873.     return(NoErr);
  1874.     }
  1875.  
  1876. // **************************************************************************
  1877. // the unload() member function frees the memory allocated to the pcx data,
  1878. // and updates the internal switches so that other member functions will
  1879. // know that the image is no longer in memory.
  1880. // **************************************************************************
  1881.  
  1882. void pcx::unload()
  1883.     {
  1884.     if (in_ram)
  1885.         {
  1886.         delete(buffer);
  1887.         in_ram = 0;
  1888.         packed = 0;
  1889.         }
  1890.     }
  1891.  
  1892. // **************************************************************************
  1893. // pcx::display can be used to display a PCX class object to screen using
  1894. // various fade types, wipes, and dissolves. All fade types other than Soft-
  1895. // Fade and SnapWipe require a screen buffer of 64000 bytes. If that memory
  1896. // is not available the function returns MemErr. The PCX will be displayed
  1897. // whether it is: on disk, in ram packed, or in ram unpacked (in order of
  1898. // decreasing execution time).
  1899. //
  1900. // The following fade types are available:
  1901. //
  1902. //        SnapWipe           - snaps the pcx to screen, basic block mem move.
  1903. //        SplitVerticalWipe  - fades from the top and bottom toward center.
  1904. //        SplitHorizWipe     - fades from the right and left toward center.
  1905. //      SlideVerticalWipe  - slides pic in from left and right
  1906. //      SlideHorizWipe     - slides pic in from top and bottom
  1907. //        VerticalDissolve   - overlays multiple vertical slices
  1908. //        HorizDissolve      - overlays multiple horizontal slices
  1909. //        SparkleDissolve    - fades with random block placement
  1910. //        SoftFade           - dac palette intensity fade, 64 passes
  1911. // **************************************************************************
  1912.  
  1913. char pcx::display(char fadetype)
  1914.     {
  1915.     char far *do_buffer;
  1916.     char loaded_here = 0;
  1917.  
  1918.     // SoftFade (palette fade) requires the palette to be cleared.
  1919.  
  1920.     if (fadetype == SoftFade)
  1921.         {
  1922.         wait_vbi();
  1923.         clrpalette(0,256);
  1924.         }
  1925.     else
  1926.  
  1927.     // all other types require the new palette to be loaded
  1928.  
  1929.         {
  1930.         wait_vbi();
  1931.         loadpalette(0,256,palette);
  1932.         }
  1933.  
  1934.     // if the image is not in ram, or is in ram compressed, then it
  1935.     // needs to be unpacked, from either disk or memory, to either the
  1936.     // video buffer or a memory buffer depending on the fade type.
  1937.  
  1938.     if ((!in_ram) || ((in_ram) && (packed)))
  1939.         {
  1940.  
  1941.         // these two fade types simply require the data unpacked to vseg.
  1942.  
  1943.         if ((fadetype == SoftFade) || (fadetype == SnapWipe))
  1944.             {
  1945.             if (unpacktoram((char far *)MK_FP(0xa000,0), 64000U) != NoErr)
  1946.                 return(SecondaryErr);
  1947.             }
  1948.         else
  1949.  
  1950.         // all the others require the data in a 64K memory buffer
  1951.         // so one is allocated, and the data is unpacked to it
  1952.  
  1953.             {
  1954.             if ((do_buffer = new char[64100U]) == NULL)
  1955.                 return(MemErr);
  1956.             if (unpacktoram(do_buffer, 64000U) != NoErr)
  1957.                 {
  1958.                 delete(do_buffer);
  1959.                 return(SecondaryErr);
  1960.                 }
  1961.             loaded_here = 1;
  1962.             }
  1963.         }
  1964.     else
  1965.  
  1966.     // if the data is in ram uncompressed it's ready to go. The only
  1967.     // action necessary is to copy it to the video buffer for the two
  1968.     // simple fade types. The buffer identifier is member data of the
  1969.     // image class, and stores a pointer to the image buffer. In both
  1970.     // cases do_buffer is assigned the value of buffer, and then the
  1971.     // operations are performed on it. This simplifies the calls to
  1972.     // the fade functions below.
  1973.  
  1974.         {
  1975.         do_buffer = buffer;
  1976.  
  1977.         // for these two fade types copy the data over to vseg
  1978.  
  1979.         if ((fadetype == SoftFade) || (fadetype == SnapWipe))
  1980.             {
  1981.             wait_vbi();
  1982.             asm {
  1983.                 push es
  1984.                 push ds
  1985.                 push cx
  1986.                 push si
  1987.                 push di
  1988.                 mov es, GRAPH_SEG
  1989.                 xor di, di
  1990.                 lds si, do_buffer
  1991.                 mov cx, 32000
  1992.                 rep movsw
  1993.                 pop di
  1994.                 pop si
  1995.                 pop cx
  1996.                 pop ds
  1997.                 pop es
  1998.                 }
  1999.             }
  2000.         }
  2001.     switch (fadetype)
  2002.         {
  2003.         case SoftFade:           fadepalettein(0,256,palette); break;
  2004.         case SplitVerticalWipe:  doSplitVerticalWipe(do_buffer); break;
  2005.         case SplitHorizWipe:     doSplitHorizWipe(do_buffer); break;
  2006.         case SlideVerticalWipe:  doSlideVerticalWipe(do_buffer); break;
  2007.         case SlideHorizWipe:     doSlideHorizWipe(do_buffer); break;
  2008.         case VerticalDissolve:   doVerticalDissolve(do_buffer); break;
  2009.         case HorizDissolve:      doHorizDissolve(do_buffer); break;
  2010.         case SparkleDissolve:    doSparkleDissolve(do_buffer); break;
  2011.         }
  2012.     if (loaded_here)
  2013.         delete(do_buffer);
  2014.     return(NoErr);
  2015.     }
  2016.  
  2017. // **************************************************************************
  2018. // remove() clears the current image from the screen using the passed fade
  2019. // type. It will clear the screen regardless of what image is on it. No
  2020. // checking is performed to be certain this function is called after a call
  2021. // to display() has been made for the object.
  2022. // **************************************************************************
  2023.  
  2024. void pcx::remove(char fadetype)
  2025.     {
  2026.     switch (fadetype)
  2027.         {
  2028.         case SoftFade:            fadepaletteout(0,256); break;
  2029.         case SnapWipe:            clearscr(0); break;
  2030.         case SplitVerticalWipe:   doSplitVerticalWipe(NULL); break;
  2031.         case SplitHorizWipe:      doSplitHorizWipe(NULL); break;
  2032.         case SlideVerticalWipe:   break;
  2033.         case SlideHorizWipe:      break;
  2034.         case VerticalDissolve:    doVerticalDissolve(NULL); break;
  2035.         case HorizDissolve:       doHorizDissolve(NULL); break;
  2036.         case SparkleDissolve:     doSparkleDissolve(NULL); break;
  2037.         }
  2038.     return;
  2039.     }
  2040.  
  2041. // **************************************************************************
  2042. // destructor frees memory allocated to pcx file, if any
  2043. // **************************************************************************
  2044.  
  2045. pcx::~pcx()
  2046.     {
  2047.     if (in_ram)
  2048.         delete(buffer);
  2049.     }
  2050.